package main

import (
	"fmt"
	"net/http"
	"os"

	"time"

	"crypto/rsa"

	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/net/publicsuffix"
)

var engine *xorm.Engine

func initDB() {
	var err error
	engine, err = xorm.NewEngine("mysql", "root:root@/db1?charset=utf8")
	if err != nil {
		panic(err)
	}
}

func getRootDomain(domain string) string {
	rootDomain, err := publicsuffix.EffectiveTLDPlusOne(domain)
	if err != nil {
		return domain // 解析失败时，返回原域名
	}
	return rootDomain
}

type Users struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func register(c *gin.Context) {
	var user Users

	if err := c.ShouldBindJSON(&user); err != nil {
		fmt.Println(err)
		c.JSON(200, gin.H{"error": "Invalid request"})
		return
	}

	// 存储用户信息到数据库
	_, err := engine.Insert(&user)
	if err != nil {
		c.JSON(200, gin.H{"error": err})
		return
	}

	// 省略密码加密和错误处理
	c.JSON(200, gin.H{"message": "User registered successfully"})
}

// 从 private.pem 文件中加载 RSA 私钥
func loadPrivateKey(filepath string) (*rsa.PrivateKey, error) {
	// 读取文件
	keyData, err := os.ReadFile(filepath)
	if err != nil {
		return nil, err
	}

	// 解析 PEM 格式的私钥
	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
	if err != nil {
		return nil, err
	}

	return privateKey, nil
}

func PostLogin(c *gin.Context) {
	var user Users
	if err := c.ShouldBind(&user); err != nil {
		c.JSON(200, gin.H{"error": "Invalid request"})
		return
	}

	// 验证用户信息
	ok, err := engine.Get(&user)
	if err != nil {
		c.JSON(200, gin.H{"error": err})
		return
	}
	if !ok {
		c.JSON(200, gin.H{"error": "密码错误"})
		return
	}

	privateKey, _ := loadPrivateKey("key/private.pem")

	// 创建 JWT
	tokenStr, err := createJWT(privateKey)
	if err != nil {
		c.JSON(500, gin.H{"error": "创建 JWT 失败"})
	}

	fmt.Println("签名后的 JWT Token:", tokenStr)

	if err != nil {
		c.JSON(500, gin.H{"error": "Failed to generate token"})
		return
	}

	// 设置 Cookie (根域名)
	rootDomain := "." + getRootDomain(c.Request.Host)
	c.SetCookie("token", tokenStr, 3600, "/", rootDomain, false, false)

	// 跳转到欢迎页面
	c.Redirect(http.StatusFound, "/welcome")

}

func GetLogin(c *gin.Context) {
	c.HTML(http.StatusOK, "login.html", nil)
}

func GetWelcome(c *gin.Context) {
	c.HTML(http.StatusOK, "welcome.html", nil)
}

func GetSignout(c *gin.Context) {
	rootDomain := "." + getRootDomain(c.Request.Host)
	c.SetCookie("token", "", -1, "/", rootDomain, false, false)
	c.JSON(200, gin.H{"msg": "退出登录成功"})
}

// 创建一个新的 JWT Token，并使用私钥签名
func createJWT(privateKey *rsa.PrivateKey) (string, error) {
	// 创建一个 JWT 声明
	claims := jwt.MapClaims{
		"user": "exampleUser",                                      // 可以根据需要修改为更多信息
		"exp":  jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 设置过期时间为24小时后
	}

	// 创建一个新的 Token
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)

	// 使用私钥签名 Token
	signedToken, err := token.SignedString(privateKey)
	if err != nil {
		return "", err
	}

	return signedToken, nil
}

func main() {
	initDB()
	r := gin.Default()

	r.LoadHTMLGlob("templates/*")
	r.POST("/register", register)
	r.POST("/login", PostLogin)
	r.GET("/login", GetLogin)
	r.GET("/signout", GetSignout)
	r.GET("/welcome", GetWelcome)
	r.Run(":8080")
}

//如果cookie退出登录，其他的子系统也将退出登录
//采用私钥 (sso) 和公钥 (单独服务)
